package server;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


/**
 * @Author YWB
 * @Date 2021/1/15
 * desc Minicat主类
 * question:开发Minicat V4.0，在已有Minicat基础上进一步扩展，
 * 模拟出webapps部署效果 磁盘上放置一个webapps目录，webapps中可以有多个项目，例如demo1、demo2、demo3...
 * 每个项目中含有servlet，可以根据请求url定位对应servlet进一步处理。
 **/
public class Bootstrap {
    /**
     * 定义socket监听端口
     */
    private int port=8080;
    private Map<String, HttpServlet> servletMap = new
            HashMap<String,HttpServlet>();

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    /**
     * Minicat启动需要初始化展开的一些操作
     */
    public void start() throws IOException {
        //解析web.xml  初始化servlet
        loadServlet();
        //创建线程池
        ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
        //创建绑定端口的套接字
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("------------>MiniCat start in port:"+port);
        /**
         * 完成1.0版本 （浏览器请求 localhost：8080,返回固定得字符串回到页面）
         */
        /*while (true){
            Socket socket = serverSocket.accept();
            //有了socket 接收到请求，
            OutputStream outputStream = socket.getOutputStream();
            String responseText= HttpProtocolUtil.getHttpHeader200("hello minicat".getBytes().length)+"hello minicat";
            outputStream.write(responseText.getBytes());
            socket.close();
        }*/
        /**
         * 完成miniCat2.0
         * 需求,封装request和response对象,返回html静态资源文件
         */

        /*while(true){
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();

            Request request = new Request(inputStream);
            Response response = new Response(socket.getOutputStream());
            response.outPutHtml(request.getUrl());
            socket.close();
        }*/

        /***
         * 3.0版本.可以请求动态资源
         */
        while(true){
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();

            Request request = new Request(inputStream);
            Response response = new Response(socket.getOutputStream());
            HttpServlet httpServlet = servletMap.get(request.getUrl());
            if(httpServlet==null){

                response.outPutHtml(request.getUrl());
            }else {
                httpServlet.service(request,response);
            }
            socket.close();
        }

        /**
         * 4.0多线程改造
         */
       /* while(true){
            Socket socket = serverSocket.accept();
            RequestProcessorr requestProcessorr = new RequestProcessorr(socket,servletMap);
            requestProcessorr.start();
        }*/
        /**
         * 5.0线程池改造
         */
        /*
        while (true){
            //监听与此套接字建立的连接并接受它
            Socket socket = serverSocket.accept();
            //Adds message tracing to the management plugin. Logs messages from the firehose in a couple of formats.
            RequestProcessor requestProcessor = new RequestProcessor(socket, servletMap);
            threadPoolExecutor.execute(requestProcessor);
        }*/

    }
    /**
     * 定义一个线程池
     */
    private ThreadPoolExecutor getThreadPoolExecutor() {
        //核心线程数
        int corePollSize=10;
        //最大线程数
        int maximumPollSize=50;
        //保持活动时间
        long keepAliveTime=100L;
        //时间单位
        TimeUnit unit = TimeUnit.SECONDS;
        //消息队列
        ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
        //线程工厂
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        //拒绝策略
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePollSize, maximumPollSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        return threadPoolExecutor;
    }

    /**
     * 解析web.xml配置，初始化servlet
     */
    private void loadServlet() {
        //加载web.xml文件
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(resourceAsStream);
            Element rootElement = document.getRootElement();
            List<Element> nodeList = rootElement.selectNodes("//servlet");
            for (int i = 0; i < nodeList.size(); i++) {
                Element element = nodeList.get(i);
                Element servletNameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletNameElement.getStringValue();
                Element servletClassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletClassElement.getStringValue();
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                servletMap.put(urlPattern, (HttpServlet)
                        Class.forName(servletClass).newInstance());

            }
        } catch (DocumentException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

    /**
     *  启动入口
     * @param args
     */
    public static void main(String[] args) {
        Bootstrap bootstrap=new Bootstrap();
        try {
            //启动MiniCat
            bootstrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 获取指定日期的毫秒级时间戳
     *
     * @param date 字符串类型的时间
     * @return 13位-毫秒级时间戳

    public long getMillisecondTimestamp(String date) {
        if (StringUtils.isNotBlank(date)) {
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Date reDate = null;
            try {
                reDate = df.parse(date);
            } catch (ParseException e) {
                log.error("日期格式错误:{}", date);
            }
            Calendar cal = Calendar.getInstance();
            cal.setTime(reDate);
            return cal.getTimeInMillis();
        }
        return 0;
    }
     */



}
